///////////////////////////////////////////////////////////////////////////////////////////////////
/// \file formic/hf/hf.h
///
/// \brief   header file for functions related to hartree fock calculations
///
///////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef FORMIC_HF_HF_HEADER
#define FORMIC_HF_HF_HEADER

#include <vector>

#include <formic/vector/vector.h>
#include <formic/vector/matrix.h>

namespace formic {

  template <class S> class Hamiltonian;

  void init_hartree_fock_commands();

  ///////////////////////////////////////////////////////////////////////////////////////////////////
  /// \brief   namespace for functions related to hartree fock calculations
  ///
  ///////////////////////////////////////////////////////////////////////////////////////////////////

  namespace hf {

    template <class S> formic::Matrix<S,int> build_rdm1(const int n,
                                                        const int np,
                                                        const formic::Matrix<S,int> & c);

    template <class S> void build_fock(const int n,
                                       const std::vector<S> & ra,
                                       const std::vector<S> & rb,
                                       const std::vector<S> & oei,
                                       const std::vector<S> & tei,
                                       std::vector<S> & f);

    template <class S> formic::Matrix<S,int> build_fock_cholesky(const int n,
                                                                 const formic::Matrix<S,int> & ra,
                                                                 const formic::Matrix<S,int> & rb,
                                                                 const formic::Hamiltonian<S> & ham,
                                                                 std::vector<S> & intermed_0,
                                                                 std::vector<S> & intermed_1);

    template <class S> void diagonalize_fock(const int n,
                                             const int np,
                                             const formic::Matrix<S,int> & f,
                                             formic::Vector<double,int> & eval,
                                             formic::Matrix<S,int> & c);

    template <class S> void build_ints(const formic::Hamiltonian<S> & ham,
                                       const int n,
                                       std::vector<S> & oei_a,
                                       std::vector<S> & oei_b,
                                       std::vector<S> & tei);

    template <class S> S alpha_energy(const int n,
                                      const formic::Hamiltonian<S> & ham,
                                      const formic::Matrix<S,int> & f,
                                      const formic::Matrix<S,int> & rdm);

  template <class S> void print_orbitals(const int n,
                                         const int na,
                                         const formic::Vector<double,int> & evals,
                                         const formic::Matrix<S,int> & c,
                                         const std::string & str);

    template <class S> formic::Vector<double,int> get_real_pmt_vec(const bool rhf,
                                                                   const int n,
                                                                   const formic::Matrix<S,int> & ca,
                                                                   const formic::Matrix<S,int> & cb); 

    template <class S> void from_real_pmt_vec(const bool rhf,
                                              const int n,
                                              const formic::Vector<double,int> & rv,
                                              formic::Matrix<S,int> & ca,
                                              formic::Matrix<S,int> & cb);

    template <class S> S build_fock_and_energy(const bool rhf,
                                               const int n,
                                               const int na,
                                               const int nb,
                                               const formic::Hamiltonian<S> & ham,
                                               const formic::Matrix<S,int> & ca,
                                               const formic::Matrix<S,int> & cb,
                                               formic::Matrix<S,int> & fa,
                                               formic::Matrix<S,int> & fb,
                                               std::vector<S> & intermed_0,
                                               std::vector<S> & intermed_1);

    template <class S> void run_scf(const bool rhf,
                                    const int n,
                                    const int na,
                                    const int nb,
                                    const int diis_delay,
                                    const formic::Hamiltonian<S> & ham,
                                    const std::vector<double> & bias,
                                    const double bias_decay,
                                    const double thresh,
                                    const int maxit,
                                    std::vector<S> & ca,
                                    std::vector<S> & cb,
                                    S & energy);

  } // end namespace hf

} // end namespace formic

#endif
